package com.sang.service.Impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sang.mapper.TbSkuMapper;
import com.sang.pojo.TbSku;
import com.sang.service.TbSkuService;
import com.sang.support.PageResult;
import com.sang.support.QueryPageBean;
import com.sang.support.Result;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@DubboService
public class TbSkuServiceImpl extends ServiceImpl<TbSkuMapper, TbSku> implements TbSkuService {

    public RestHighLevelClient initClient() {
        //连接ES
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost(
                                "192.168.200.129", 9200, "http"))
                        .setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
                            // 该方法接收一个RequestConfig.Builder对象，对该对象进行修改后然后返回。
                            @Override
                            public RequestConfig.Builder customizeRequestConfig(
                                    RequestConfig.Builder requestConfigBuilder) {
                                return requestConfigBuilder.setConnectTimeout(5000 * 1000) // 连接超时（默认为1秒）
                                        .setSocketTimeout(6000 * 1000);// 套接字超时（默认为30秒）//更改客户端的超时限制默认30秒现在改为100*1000分钟
                            }
                        }));// 调整最大重试超时时间（默认为30秒）.setMaxRetryTimeoutMillis(60000);)
        return client;
    }

    @Override
    public void add() {

        RestHighLevelClient client = this.initClient();
        //创建索引库
        CreateIndexRequest request = new CreateIndexRequest("sku");
        request.settings(Settings.builder()  //三个分片  一个副本
//                .put("index.number_of_shards", 3)
//                .put("index.number_of_replicas", 1)
                .put("index.max_result_window", 500000));
        request.mapping("{\n" +
                " \"properties\": {\n" +
                "      \"id\" : {\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"sn\": {\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"name\" :{\n" +
                "        \"type\": \"text\",\n" +
                "        \"analyzer\": \"ik_smart\"\n" +
                "      },\n" +
                "      \"price\" : {\n" +
                "        \"type\": \"integer\"\n" +
                "      },\n" +
                "      \"num\":{\n" +
                "        \"type\": \"integer\",\n" +
                "       \"index\": false\n" +
                "      },\n" +
                "      \"alertNum\" :{\n" +
                "        \"type\": \"integer\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"image\" :{\n" +
                "        \"type\": \"keyword\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"images\" : {\n" +
                "        \"type\": \"keyword\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"weight\":{\n" +
                "        \"type\": \"integer\",\n" +
                "        \"index\": true\n" +
                "      },\n" +
                "      \"createTime\" :{\n" +
                "        \"type\": \"date\"\n" +
                "      },\n" +
                "      \"updateTime\" :{\n" +
                "        \"type\": \"date\"\n" +
                "      },\n" +
                "      \"spuId\" :{\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"categoryId\":{\n" +
                "        \"type\": \"integer\"\n" +
                "      },\n" +
                "      \"categoryName\":{\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"brandName\" : {\n" +
                "        \"type\": \"text\"\n" +
                "      },\n" +
                "      \"spec\":{\n" +
                "        \"type\": \"keyword\"\n" +
                "      },\n" +
                "      \"saleNum\" :{\n" +
                "        \"type\": \"integer\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"commentNum\":{\n" +
                "        \"type\": \"binary\",\n" +
                "        \"index\": false\n" +
                "      },\n" +
                "      \"status\": {\n" +
                "        \"type\": \"keyword\",\n" +
                "        \"index\": false\n" +
                "      }\n" +
                "    }\n" +
                "}", XContentType.JSON);
        try {
            //构建索引库
            CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("构建索引库失败");

        }
        System.out.println("mapping构建成功,开始插入数据");
        //从数据库中读取数据
        List<TbSku> tbSkus = this.list();
        System.out.println("一共查询到" + tbSkus.size() + "条数据");
        BulkRequest bulkRequest = new BulkRequest();
        int i = 0;
        for (TbSku tbSku : tbSkus) {
            i++;
            bulkRequest.add(new IndexRequest("sku")
                    .id(tbSku.getId())
                    .source(JSON.toJSONString(tbSku), XContentType.JSON)
            );
            if (i == 10000) {
                BulkResponse bulkResponse = null;
                try {
                    bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (!bulkResponse.hasFailures()) {
                    System.out.println("数据导入成功");
                    bulkRequest = new BulkRequest();
                    bulkRequest.timeout(TimeValue.timeValueMinutes(1));
                    i = 0;
                } else {
                    throw new RuntimeException("导入数据失败");
                }
            }
        }
        // 4.发起请求
        System.out.println("稍等哈");
        BulkResponse bulkResponse = null;
        try {
            bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
            System.out.println(bulkResponse.status());
            client.close();
            System.out.println("response = " + bulkResponse.status());
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Result findAll(QueryPageBean queryPageBean) {
        RestHighLevelClient client = this.initClient();
        // 1.创建SearchSourceBuilder对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //通过布尔查询 查询所有后在把数据进行分页
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //名字为空的话  优先查询所有
        if(ObjectUtils.isEmpty(queryPageBean.getQueryName())&&!"".equals(queryPageBean.getQueryName())){
            System.out.println("查询所有的页面");
            MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
            boolQueryBuilder.must(matchAllQueryBuilder);
        }
        //名字不为空  先按名字查找
        if (!ObjectUtils.isEmpty(queryPageBean.getQueryName())&&!"".equals(queryPageBean.getQueryName())) {
            System.out.println("按照商品名称查找");
            MatchQueryBuilder name = QueryBuilders.matchQuery("name", queryPageBean.getQueryName());
            boolQueryBuilder.must(name);
        }
        //价格不为空  按照价格区间查找
        if (!ObjectUtils.isEmpty(queryPageBean.getMaxPrice())) {
            System.out.println("按照价格区间查找");
            RangeQueryBuilder price = QueryBuilders.rangeQuery("price").gte(queryPageBean.getMinPrice()).lte(queryPageBean.getMaxPrice());
            boolQueryBuilder.filter(price);
        }
        //排序条件,互斥    销量排序
        sourceBuilder.query(boolQueryBuilder);
        // `sourceBuilder.query(queryBuilder)`后添加排序
        if (!ObjectUtils.isEmpty(queryPageBean.getSaleNum())) {
            if (queryPageBean.getSaleNum() == 1) {
                sourceBuilder.sort("saleNum", SortOrder.ASC);
                //正序排序
            } else if (queryPageBean.getSaleNum() == 0) {
                //倒序排序
                sourceBuilder.sort("saleNum", SortOrder.DESC);
            }
        }
        //排序条件   价格排序
        if (!ObjectUtils.isEmpty(queryPageBean.getPrice())) {
            if (queryPageBean.getPrice() == 1) {
                sourceBuilder.sort("price", SortOrder.ASC);
                //正序排序
            } else if (queryPageBean.getPrice() == 0) {
                //倒序排序
                sourceBuilder.sort("price", SortOrder.DESC);
            }
        }
        //排序条件   评论数排序
        if (!ObjectUtils.isEmpty(queryPageBean.getCommentNum())) {
            if (queryPageBean.getCommentNum() == 1) {
                sourceBuilder.sort("commentNum", SortOrder.ASC);
                //正序排序
            } else if (queryPageBean.getCommentNum() == 0) {
                //倒序排序
                sourceBuilder.sort("commentNum", SortOrder.DESC);
            }
        }


        PageResult pageResult;

        // 如果传来的分页参数不为空这里就分页一次  分页查询  传来两个入参
        int from = (queryPageBean.getCurrentPage() - 1) * queryPageBean.getPageSize();
        sourceBuilder.from(from);
        sourceBuilder.size(queryPageBean.getPageSize());

        // 2.创建SearchRequest对象，并指定索引库名称
        SearchRequest request = new SearchRequest("sku");
        List<TbSku> list = new ArrayList<>();
        try {

            //高亮设置在提交请求之前
            HighlightBuilder highlight = SearchSourceBuilder.highlight();
            highlight.field("name");  // 高亮显示域
            highlight.preTags("<font color='red'>"); // 高亮显示前缀
            highlight.postTags("</font>");  // 高亮显示后缀
            sourceBuilder.highlighter(highlight);
            //请求
            request.source(sourceBuilder);
            //查询到所有的结果  通过前端来显示
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            SearchHit[] hits = response.getHits().getHits();



            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                TbSku tbSku = JSON.parseObject(sourceAsString, TbSku.class);

                HighlightField highlightField = hit.getHighlightFields().get("name");
                if (!ObjectUtils.isEmpty(highlightField)) {
                    Text[] fragments = highlightField.fragments();
                    String join = StringUtils.join(fragments);
                    tbSku.setName(join);
                }
                list.add(tbSku);
            }
            System.out.println(response.getHits().getTotalHits().value);
            pageResult = new PageResult(response.getHits().getTotalHits().value, list);
            System.out.println(pageResult);
            System.out.println("数组长度为" + list.size());
            return Result.build(pageResult);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.buildError("参数错误");
    }

    /**
     * 通过搜索框查询含有相关字段的商品
     *
     * @param name 这里是搜索条件
     * @return 返回值是查询到的结果集
     */
//    @Override
    public Result findByName(String name) {
        RestHighLevelClient client = this.initClient();
        List<TbSku> list = new ArrayList<>();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        boolQueryBuilder.must(QueryBuilders.matchQuery("name", name));

        sourceBuilder.query(boolQueryBuilder);
        HighlightBuilder highlight = SearchSourceBuilder.highlight();
        highlight.field("name");  // 高亮显示域
        highlight.preTags("<font color='red'>"); // 高亮显示前缀
        highlight.postTags("</font>");  // 高亮显示后缀
        sourceBuilder.highlighter(highlight);

        // 2.创建SearchRequest对象，并指定索引库名称
        SearchRequest request = new SearchRequest("sku");
        // 3.添加SearchSourceBuilder对象到SearchRequest对象中
        request.source(sourceBuilder);
        // 4.发起请求，得到结果
        try {
            //查询到所有的结果  通过前端来显示
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            SearchHit[] hits = response.getHits().getHits();


            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                HighlightField highlightField = hit.getHighlightFields().get("name");
                Text[] fragments = highlightField.fragments();
                String join = StringUtils.join(fragments);


                TbSku tbSku = JSON.parseObject(sourceAsString, TbSku.class);
                tbSku.setName(join);
                list.add(tbSku);
            }
            client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.build(list);
    }


}
